﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

using Perseus;
using Perseus.Plugins;
using Perseus.Xml;

using Hetymine.Executioner.Controls;
using Hetymine.Executioner.Plugins;
using Hetymine.Executioner.Triggers;

namespace Hetymine.Executioner.Commands {
    public class TriggerCommand : ICommand {
        private static TriggerCommandConfigurator _Configurator;

        public TriggerCommand() {
            this.Name = string.Empty;
            this.CallStrings = new List<string>();
            this.Commands = new List<CommandInfo>();            
            this.Triggers = new List<ITrigger>();
        }

        public List<CommandInfo> Commands { get; set; }
        public List<ITrigger> Triggers { get; set; }

        #region ICommand Members
        public string Name { get; set; }        
        public bool IsEmpty {
            get {
                if (this.Commands.Count < 1) {
                    return true;
                }

                if (this.Commands.Count == 1 && this.Commands[0].IsEmpty) {
                    return true;
                }

                if (this.CallStrings.Count > 0) {
                    return false;
                }

                foreach (ITrigger trigger in this.Triggers) {
                    if (!trigger.IsEmpty) {
                        return false;
                    }
                }
                
                return true;
            }
        }

        public void Load(XElement element) {
            this.Name = element.Element("Name").ValueOrEmpty();

            var commands = from c in element.Elements("Command")
                           select c;

            foreach (var c in commands) {
                this.Commands.Add(new CommandInfo(c));
            }

            if (element.Element("Triggers") != null) {
                var triggers = from t in element.Element("Triggers").Elements()
                               select t;

                foreach (var t in triggers) {
                    switch (t.Name.LocalName) {
                        case "CallString":                           
                            if (!t.Value.IsEmpty()) {
                                this.CallStrings.Add(t.Value);
                            }
                            break;
                        case "HotKey":
                            if (!t.Value.IsEmpty()) {
                                HotKeyTrigger hotKeyTrigger = new HotKeyTrigger();
                                hotKeyTrigger.HotKey = t.Value;
                                this.Triggers.Add(hotKeyTrigger);
                            }
                            break;
                        case "Speech":
                            SpeechTrigger speechTrigger = new SpeechTrigger();
                            speechTrigger.Phrase = t.Value;
                            this.Triggers.Add(speechTrigger);
                            break;
                        default:
                            try {
                                PluginInstance<Plugin> plugin = Executioner.PluginService[typeof(TriggerPlugin), t.Name.LocalName];
                                if (plugin != null) {
                                    TriggerPlugin tp = plugin.Instance as TriggerPlugin;
                                    if (tp.CanInitialize) {
                                        Hetymine.Executioner.Triggers.ITrigger trigger = tp.InitializeTrigger();
                                        trigger.Load(t);
                                        if (!trigger.IsEmpty) {
                                            this.Triggers.Add(trigger);
                                        }
                                    }
                                }
                            }
                            catch {
                                App.Log("Error loading " + t.Name.LocalName + " plugin trigger.");
                            }
                            break;
                    }
                }
            }
        }
        public XElement Save() {
            if (this.IsEmpty) {
                return null;
            }

            XElement xe = new XElement("Trigger");

            xe.Add(new XElement("Name", this.Name));

            foreach (CommandInfo ci in this.Commands) {
                XElement cmd = new XElement("Command", ci.Command);
                if (!ci.Arguments.IsEmpty()) {
                    cmd.Add(new XAttribute("Args", ci.Arguments));
                }
                xe.Add(cmd);
            }

            XElement triggers = new XElement("Triggers");
            
            foreach (string cs in this.CallStrings) {
                triggers.Add(new XElement("CallString", cs));
            }

            foreach (ITrigger t in this.Triggers) {
                XElement trigger = t.Save();
                if (trigger != null) {
                    triggers.Add(trigger);
                }
            }

            xe.Add(triggers);

            return xe;
        }

        public List<string> CallStrings { get; set; }
        public bool Execute(string parameters) {
            bool success = true;

            foreach (CommandInfo c in this.Commands) {
                if (!Executioner.ExecuteProcessCommand(c.Command, c.Arguments)) {
                    success = false;
                }
            }

            return success;
        }

        public ICommandConfigurator<ICommand> Configurator {
            get {
                if (TriggerCommand._Configurator == null) {
                    TriggerCommand._Configurator = new TriggerCommandConfigurator();
                }
                TriggerCommand._Configurator.InitializeConfig(this);
                return TriggerCommand._Configurator;
            }
        }

        public object Clone() {
            TriggerCommand tc = (TriggerCommand)this.MemberwiseClone();

            tc.CallStrings = new List<string>();
            foreach (string cs in this.CallStrings) {
                tc.CallStrings.Add(cs);
            }

            tc.Commands = new List<CommandInfo>();
            foreach (CommandInfo ci in this.Commands) {
                tc.Commands.Add(new CommandInfo(ci.Command, ci.Arguments));
            }

            tc.Triggers = new List<ITrigger>();
            foreach (ITrigger t in this.Triggers) {
                tc.Triggers.Add((ITrigger)t.Clone());
            }

            return tc;            
        }
        #endregion
    }
}
